using Fantasy.SourceGenerator.Common;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// ReSharper disable AssignNullToNotNullAttribute

namespace Fantasy.SourceGenerator.Generators
{
    /// <summary>
    /// Event System 注册代码生成器
    /// 自动生成 EventComponent 所需的 Event System 注册代码，替代运行时反射
    /// </summary>
    [Generator]
    public partial class EventSystemGenerator : IIncrementalGenerator
    {
        public void Initialize(IncrementalGeneratorInitializationContext context)
        {
            // 查找所有实现了 EventSystem 相关抽象类的类
            var eventSystemTypes = context.SyntaxProvider
                .CreateSyntaxProvider(
                    predicate: static (node, _) => IsEventSystemClass(node),
                    transform: static (ctx, _) => GetEventSystemTypeInfo(ctx))
                .Where(static info => info != null)
                .Collect();
            // 组合编译信息和找到的类型
            var compilationAndTypes = context.CompilationProvider.Combine(eventSystemTypes);
            // 注册源代码输出
            context.RegisterSourceOutput(compilationAndTypes, static (spc, source) =>
            {
                // 检查1: 是否定义了 FANTASY_NET 或 FANTASY_UNITY 预编译符号
                if (!CompilationHelper.HasFantasyDefine(source.Left))
                {
                    return;
                }

                // 检查2: 是否引用了 Fantasy 框架的核心类型
                if (source.Left.GetTypeByMetadataName("Fantasy.Assembly.IEventSystemRegistrar") == null)
                {
                    return;
                }

                GenerateRegistrationCode(spc, source.Left, source.Right!);
            });
        }

        /// <summary>
        /// 提取 EventSystem 类型信息
        /// </summary>
        private static EventSystemTypeInfo? GetEventSystemTypeInfo(GeneratorSyntaxContext context)
        {
            var classDecl = (ClassDeclarationSyntax)context.Node;
            
            if (context.SemanticModel.GetDeclaredSymbol(classDecl) is not INamedTypeSymbol symbol || !symbol.IsInstantiable())
            {
                return null;
            }

            if (symbol.BaseType == null)
            {
                return null;
            }
            
            var baseType = symbol.BaseType;

            if (!baseType.IsGenericType)
            {
                return null;
            }

            return baseType.Name switch
            {
                "EventSystem" => EventSystemTypeInfo.Create(EventSystemType.EventSystem, symbol),
                "AsyncEventSystem" => EventSystemTypeInfo.Create(EventSystemType.AsyncEventSystem, symbol),
                "SphereEventSystem" => EventSystemTypeInfo.Create(EventSystemType.SphereEventSystem, symbol),
                _ => null
            };
        }
        
        /// <summary>
        /// 生成注册代码
        /// </summary>
        private static void GenerateRegistrationCode(
            SourceProductionContext context,
            Compilation compilation,
            IEnumerable<EventSystemTypeInfo> eventSystemTypes)
        {
            var eventSystems = eventSystemTypes.ToList();
            // 获取当前程序集名称（仅用于注释）
            var assemblyName = compilation.AssemblyName ?? "Unknown";
            // 生成代码文件
            var builder = new SourceCodeBuilder();
            // 添加文件头
            builder.AppendLine(GeneratorConstants.AutoGeneratedHeader);
            // 添加 using
            builder.AddUsings(
                "System",
                "System.Collections.Generic",
                "Fantasy.Assembly",
                "Fantasy.DataStructure.Collection",
                "Fantasy.Event"
            );
            builder.AppendLine();
            // 开始命名空间（固定使用 Fantasy.Generated）
            builder.BeginNamespace("Fantasy.Generated");
            // 开始类定义（实现 IEventSystemRegistrar 接口）
            builder.AddXmlComment($"Auto-generated Event System registration class for {assemblyName}");
            builder.BeginClass("EventSystemRegistrar", "internal sealed", "IEventSystemRegistrar");
            // 生成字段用于存储已注册的事件处理器（用于 UnRegister）
            GenerateFields(builder, eventSystems);
            // 生成 RegisterSystems 方法
            GenerateRegisterMethod(builder, eventSystems);
            // 生成 UnRegisterSystems 方法
            GenerateUnRegisterMethod(builder, eventSystems);
            // 生成 Dispose 方法
            GenerateDisposeMethod(builder, eventSystems);
            // 结束类和命名空间
            builder.EndClass();
            builder.EndNamespace();
            // 输出源代码
            context.AddSource("EventSystemRegistrar.g.cs", builder.ToString());
        }

        /// <summary>
        /// 生成字段，用于存储已注册的事件处理器实例
        /// </summary>
        private static void GenerateFields(SourceCodeBuilder builder, List<EventSystemTypeInfo> eventSystems)
        {
            builder.AddComment("Store registered event handlers for UnRegister");

            if (!eventSystems.Any())
            {
                return;
            }
            
            foreach (var eventSystemTypeInfo in eventSystems)
            {
                var fieldName = $"_{eventSystemTypeInfo.TypeName.ToCamelCase()}";
                builder.AppendLine($"private {eventSystemTypeInfo.TypeFullName} {fieldName} = new {eventSystemTypeInfo.TypeFullName}();");
            }
            builder.AppendLine();
        }
        
        /// <summary>
        /// 生成 RegisterSystems 方法
        /// </summary>
        private static void GenerateRegisterMethod(SourceCodeBuilder builder, List<EventSystemTypeInfo> eventSystems)
        {
            builder.AddXmlComment("Register all Event Systems to the containers");
            builder.BeginMethod(
                "public void RegisterSystems(" +
                "OneToManyList<Type, IEvent> events, " +
                "OneToManyList<Type, IEvent> asyncEvents, " +
                "OneToManyList<Type, IEvent> sphereEvents)");

            if (eventSystems.Any())
            {
                foreach (var eventSystemTypeInfo in eventSystems)
                {
                    var fieldName = $"_{eventSystemTypeInfo.TypeName.ToCamelCase()}";
                    
                    switch (eventSystemTypeInfo.EventSystemType)
                    {
                        case EventSystemType.EventSystem:
                        {
                            builder.AppendLine($"events.Add({fieldName}.EventType(), {fieldName});");
                            continue;
                        }
                        case EventSystemType.AsyncEventSystem:
                        {
                            builder.AppendLine($"asyncEvents.Add({fieldName}.EventType(), {fieldName});");
                            continue;
                        }
                        case EventSystemType.SphereEventSystem:
                        {
                            builder.AppendLine($"sphereEvents.Add({fieldName}.EventType(), {fieldName});");
                            continue;
                        }
                    }
                }
            }
        
            builder.EndMethod();
            builder.AppendLine();
        }
        
        /// <summary>
        /// 生成 UnRegisterSystems 方法
        /// </summary>
        private static void GenerateUnRegisterMethod(SourceCodeBuilder builder, List<EventSystemTypeInfo> eventSystems)
        {
            builder.AddXmlComment("Unregister all Event Systems from the containers (called on hot reload)");
            builder.BeginMethod(
                "public void UnRegisterSystems(" +
                "OneToManyList<Type, IEvent> events, " +
                "OneToManyList<Type, IEvent> asyncEvents, " +
                "OneToManyList<Type, IEvent> sphereEvents)");
            
            if (eventSystems.Any())
            {
                foreach (var eventSystemTypeInfo in eventSystems)
                {
                    var fieldName = $"_{eventSystemTypeInfo.TypeName.ToCamelCase()}";
                    
                    switch (eventSystemTypeInfo.EventSystemType)
                    {
                        case EventSystemType.EventSystem:
                        {
                            builder.AppendLine($"events.RemoveValue({fieldName}.EventType(), {fieldName});");
                            continue;
                        }
                        case EventSystemType.AsyncEventSystem:
                        {
                            builder.AppendLine($"asyncEvents.RemoveValue({fieldName}.EventType(), {fieldName});");
                            continue;
                        }
                        case EventSystemType.SphereEventSystem:
                        {
                            builder.AppendLine($"sphereEvents.RemoveValue({fieldName}.EventType(), {fieldName});");
                            continue;
                        }
                    }
                }
            }
        
            builder.EndMethod();
            builder.AppendLine();
        }
        
        /// <summary>
        /// 生成 Dispose 方法
        /// </summary>
        private static void GenerateDisposeMethod(SourceCodeBuilder builder, List<EventSystemTypeInfo> eventSystems)
        {
            builder.AddXmlComment("Dispose all resources");
            builder.BeginMethod("public void Dispose()");
            builder.AddComment("Clear all references");

            if (eventSystems.Any())
            {
                foreach (var eventSystemTypeInfo in eventSystems)
                {
                    var fieldName = $"_{eventSystemTypeInfo.TypeName.ToCamelCase()}";
                    builder.AppendLine($"{fieldName} = null;");
                }
            }

            builder.EndMethod();
        }
        
        /// <summary>
        /// 快速判断语法节点是否可能是 EventSystem 类
        /// </summary>
        private static bool IsEventSystemClass(SyntaxNode node)
        {
            if (node is not ClassDeclarationSyntax classDecl)
            {
                return false;
            }

            // 必须有基类型列表（继承抽象类）
            if (classDecl.BaseList == null || classDecl.BaseList.Types.Count == 0)
            {
                return false;
            }

            // 快速检查是否包含可能的 EventSystem 基类名称
            var baseListText = classDecl.BaseList.ToString();
            return baseListText.Contains("AwakeSystem") ||
                   baseListText.Contains("AsyncEventSystem") ||
                   baseListText.Contains("SphereEventSystem");
        }
        
        private enum EventSystemType
        {
            None,
            EventSystem,            // EventSystem<T> 事件类
            AsyncEventSystem,       // AsyncEventSystem<T> 事件类
            SphereEventSystem,      // SphereEventSystem<T> 事件类
        }
        
        private sealed class EventSystemTypeInfo
        {
            public readonly EventSystemType EventSystemType;
            public readonly string TypeFullName;
            public readonly string TypeName;

            private EventSystemTypeInfo(EventSystemType eventSystemType, string typeFullName, string typeName)
            {
                EventSystemType = eventSystemType;
                TypeFullName = typeFullName;
                TypeName = typeName;
            }

            public static EventSystemTypeInfo Create(EventSystemType eventSystemType, INamedTypeSymbol symbol)
            {
                return new EventSystemTypeInfo(
                    eventSystemType,
                    symbol.GetFullName(),
                    symbol.Name);
            }
        }
    }
}
